package com.milling.business.service.impl;

import java.util.List;
import java.util.Map;

import com.alibaba.fastjson2.JSONObject;
import com.milling.business.BusinessConstants;
import com.milling.business.domain.*;
import com.milling.business.mapper.WmsCellInfoMapper;
import com.milling.business.mapper.WmsNeedleCacheMapper;
import com.milling.business.mapper.WmsTaskInfoMapper;
import com.milling.common.core.redis.RedisCache;
import com.milling.common.utils.DateUtils;
import com.milling.common.utils.http.HttpUtils;
import com.milling.common.utils.modbus.ModbusServiceFactory;
import com.milling.common.utils.modbus.ModbusTcpService;
import com.milling.common.utils.sql.DbUtils;
import com.milling.common.utils.uuid.UUID;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.milling.business.mapper.WmsTxnInfoMapper;
import com.milling.business.service.IWmsTxnInfoService;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;

/**
 *
 * 20250317 晚21：50
 *
 * 28  22
 *
 * 16  17 行空缺        5  6  7         16  17  18
 *
 * 双面共 1208          单面 604
 *
 * 交易信息Service业务层处理
 *
 * @author X
 * @date 2025-01-17
 */
@Service
public class WmsTxnInfoServiceImpl implements IWmsTxnInfoService
{
    private static final Logger logger = LoggerFactory.getLogger(WmsTxnInfoServiceImpl.class);

    // 从参数中读取IP、端口、slaveId和连接池大小
    @Value("${modbus.tcp.host}")
    private String host; // 从配置文件或命令行参数中读取

    @Value("${modbus.tcp.port}")
    private int port; // 从配置文件或命令行参数中读取

    @Value("${modbus.tcp.poolSize}")
    private int poolSize; // 从配置文件或命令行参数中读取

    @Value("${modbus.tcp.slaveId}")
    private int slaveId;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private WmsTxnInfoMapper wmsTxnInfoMapper;

    @Autowired
    private WmsTaskInfoMapper wmsTaskInfoMapper;

    @Autowired
    private WmsCellInfoMapper wmsCellInfoMapper;

    @Autowired
    private WmsNeedleCacheMapper wmsNeedleCacheMapper;

    @Autowired
    private WmsNeedleCacheServiceImpl wmsNeedleCacheService;

    @Autowired
    private DbUtils dbUtils;

    // 从参数中读取后库接口地址参数
    @Value("${wcs.tcp.host}")
    private String urlhost;

    @Value("${wcs.tcp.queryInventory}")
    private String queryInventory;

    @Value("${wcs.tcp.requestMaterial}")
    private String requestMaterial; // 从配置文件或命令行参数中读取

    @Value("${wcs.tcp.queryDrillinfoByBoxid}")
    private String queryDrillinfoByBoxid;

    // 获取Modbus服务实例
    private ModbusTcpService modbusTcpService;

    @PostConstruct
    public void init() {
        // 初始化 Modbus 服务
        modbusTcpService = ModbusServiceFactory.getModbusService(host, port, poolSize);
        logger.info("WmsTxnInfoServiceImpl Modbus服务初始化完成 - {}:{}", host, port);

        // 初始化扫码器连接
//        initConnection();
    }
    /**
     * 查询交易信息
     *
     * @param txnId 交易信息主键
     * @return 交易信息
     */
    @Override
    public WmsTxnInfo selectWmsTxnInfoByTxnId(String txnId)
    {
        return wmsTxnInfoMapper.selectWmsTxnInfoByTxnId(txnId);
    }

    /**
     * 查询交易信息列表
     *
     * @param wmsTxnInfo 交易信息
     * @return 交易信息
     */
    @Override
    public List<WmsTxnInfo> selectWmsTxnInfoList(WmsTxnInfo wmsTxnInfo)
    {
        return wmsTxnInfoMapper.selectWmsTxnInfoList(wmsTxnInfo);
    }

    /**
     * 新增交易信息
     *
     * @param wmsTxnInfo 交易信息
     * @return 结果
     */
    @Override
    public int insertWmsTxnInfo(WmsTxnInfo wmsTxnInfo)
    {
        wmsTxnInfo.setCreateTime(DateUtils.getNowDate());
        return wmsTxnInfoMapper.insertWmsTxnInfo(wmsTxnInfo);
    }

    /**
     * 修改交易信息
     *
     * @param wmsTxnInfo 交易信息
     * @return 结果
     */
    @Override
    public int updateWmsTxnInfo(WmsTxnInfo wmsTxnInfo)
    {
        wmsTxnInfo.setUpdateTime(DateUtils.getNowDate());
        return wmsTxnInfoMapper.updateWmsTxnInfo(wmsTxnInfo);
    }

    /**
     * 批量删除交易信息
     *
     * @param txnIds 需要删除的交易信息主键
     * @return 结果
     */
    @Override
    public int deleteWmsTxnInfoByTxnIds(String[] txnIds)
    {
        return wmsTxnInfoMapper.deleteWmsTxnInfoByTxnIds(txnIds);
    }

    /**
     * 删除交易信息信息
     *
     * @param txnId 交易信息主键
     * @return 结果
     */
    @Override
    public int deleteWmsTxnInfoByTxnId(String txnId)
    {
        return wmsTxnInfoMapper.deleteWmsTxnInfoByTxnId(txnId);
    }


    @Transactional
    public int processRequestMaterial(WmsTxnInfo wmsTxnInfo) {
        int returncode = 0;
        wmsNeedleCacheService.syncNeeldStatusA();

        JSONObject jsonObject = JSONObject.parseObject(wmsTxnInfo.getReqBody());

        String macCode = jsonObject.getString("macCode");
        Long m_Drill_ID = jsonObject.getLong("m_Drill_ID");
        Long m_Drill_PortID = jsonObject.getLong("m_Drill_PortID");
        Long m_Drill_Location = jsonObject.getLong("m_Drill_Location");
        Long m_Delivery_Type = jsonObject.getLong("m_Delivery_Type");
        Long drillCount = jsonObject.getLong("m_Drill_Count");

        wmsTxnInfo.setCreateTime(DateUtils.getNowDate());
        wmsTxnInfo.setMacCode(macCode);
        wmsTxnInfo.setCreateBy("MacCode:" + macCode);
//        wmsTxnInfo.setTxnId(UUID.randomUUID().toString());
        wmsTxnInfo.setUpdateTime(DateUtils.getNowDate());
        wmsTxnInfoMapper.insertWmsTxnInfo(wmsTxnInfo);

        try {
//            (ObjectPool<ModbusMaster> modbusMasterPool = ModbusMasterPoolFactory.createPool(host, port, poolSize))
//            ModbusTcpService modbusTcpService = new ModbusTcpServiceImpl(modbusMasterPool);

            if (m_Delivery_Type == 1) {
                returncode = handleDeliveryType1(jsonObject, wmsTxnInfo, macCode, modbusTcpService, drillCount, m_Drill_ID, m_Drill_PortID);
            } else if (m_Delivery_Type == 2) {
                returncode = handleDeliveryType2(wmsTxnInfo, macCode, modbusTcpService, m_Drill_ID, m_Drill_PortID, drillCount);
            }
        } catch (Exception e) {
            logger.error("Modbus 连接池创建失败", e);
            returncode = 7;
        }

        return returncode;
    }

    private int handleDeliveryType1(JSONObject jsonObject, WmsTxnInfo wmsTxnInfo, String macCode, ModbusTcpService modbusTcpService, Long drillCount, Long m_Drill_ID, Long m_Drill_PortID) {
        int returncode = 0;

        String drillSize = jsonObject.getString("m_Drill_Size");
        Long drillGrindCount = jsonObject.getLong("m_Drill_GrindCount");
        String drillEdge = jsonObject.getString("m_Drill_Edge");
        String drillFactory = jsonObject.getString("m_Drill_Factory");
        String drillType = jsonObject.getString("m_Drill_Type");
        String drillInfo = jsonObject.getString("m_Drill_Info");

        logger.info("下料开始");

        WmsCellInfo wmsCellInfo = new WmsCellInfo();
        wmsCellInfo.setDrillInfo(drillInfo);
        wmsCellInfo.setCellStatus(BusinessConstants.CELL_STATUS_3);
        List<WmsCellInfo> list2 = wmsCellInfoMapper.selectWmsCellInfoList(wmsCellInfo);

        Integer place = findPlace(list2, drillCount);

        if (drillCount == 50) { // 上料托盘 整盒补料
            if (place > 0) {
                try {
                    writeAndGenerateTask(modbusTcpService, wmsTxnInfo, macCode, place, m_Drill_PortID, m_Drill_ID, drillCount);
                    updateCellStatus(wmsCellInfoMapper, place, BusinessConstants.CELL_STATUS_4);
                } catch (ModbusTransportException e) {
                    logger.error("写入寄存器地址失败", e);
                    returncode = 1;
                }
            } else {
                returncode = handleFullBoxRequest(jsonObject, wmsTxnInfo, macCode, drillCount, drillInfo, m_Drill_ID, modbusTcpService);
            }
        } else { // 配针托盘补料
            int needlePlace = findNeedlePlace(redisCache);
            if (place > 0 && needlePlace > 0) {
                try {
                    writeAndGenerateTask(modbusTcpService, wmsTxnInfo, macCode, place, m_Drill_PortID, m_Drill_ID, drillCount);
                    updateCellStatus(wmsCellInfoMapper, place, BusinessConstants.CELL_STATUS_4);
                } catch (ModbusTransportException e) {
                    logger.error("写入寄存器地址失败", e);
                    returncode = 4;
                }
            } else {
                returncode = handleCacheRequest(jsonObject, wmsTxnInfo, macCode, drillCount, drillInfo, modbusTcpService);
            }
        }

        return returncode;
    }

    private int handleDeliveryType2(WmsTxnInfo wmsTxnInfo, String macCode, ModbusTcpService modbusTcpService, Long m_Drill_ID, Long m_Drill_PortID, Long drillCount) {
        int returncode = 0;

        WmsNeedleCache wmsNeedleCache = wmsNeedleCacheMapper.selectWmsNeedleCacheByNeedleId(m_Drill_ID);
        if (wmsNeedleCache != null) {
            wmsNeedleCache.setStatus(BusinessConstants.NEEDLE_STATUS_3);
            wmsNeedleCacheMapper.updateWmsNeedleCache(wmsNeedleCache);

            int place = findEmptyCell(dbUtils);
            if (place > 0) {
                try {
                    writeBackflowTasks(modbusTcpService, wmsTxnInfo, macCode, m_Drill_ID, m_Drill_PortID, place, drillCount, wmsNeedleCache);
                } catch (ModbusTransportException e) {
                    logger.error("写入回流寄存器地址失败", e);
                    returncode = 6;
                }
            } else {
                logger.error("缓存立库无空余位，无法回流");
                returncode = 3;
            }
        }

        return returncode;
    }

    // 辅助方法：查找位置
    private Integer findPlace(List<WmsCellInfo> list, Long drillCount) {
        for (WmsCellInfo cell : list) {
            if (drillCount <= cell.getDrillCount()) {
                return cell.getCellId().intValue();
            }
        }
        //盘，选择有货托盘
        for (WmsCellInfo cell : list) {
            if (drillCount <= cell.getDrillCount()) {
                logger.info("选择有货托盘位置: {}", cell.getCellId());
                return cell.getCellId().intValue();
            }
        }

        logger.warn("未找到合适的托盘位置，所需容量: {}", drillCount);
        return 0;
    }

    // 辅助方法：查找针位置 - 增加数据库状态检查
    private int findNeedlePlace(RedisCache redisCache) {
        for (int i = 1; i < 85; i++) {
            // 检查Redis缓存
            Object cacheObj = redisCache.getCacheObject("NEEDLE_ID" + i);
            String needleCache = (cacheObj != null) ? cacheObj.toString() : "0";

            if (needleCache == null || "0".equals(needleCache)) {
                // 进一步检查数据库中的实际状态
                WmsNeedleCache dbNeedleCache = wmsNeedleCacheMapper.selectWmsNeedleCacheByNeedleId((long) i);
                if (dbNeedleCache != null) {
                    // 如果数据库中显示为空闲状态，才返回这个位置
                    if (BusinessConstants.NEEDLE_STATUS_1.equals(dbNeedleCache.getStatus()) ||
                            dbNeedleCache.getDrillCount() == null ||
                            dbNeedleCache.getDrillCount() == 0) {
                        logger.info("找到空闲配针缓存位: {}, Redis缓存: {}, DB状态: {}",
                                i, needleCache, dbNeedleCache.getStatus());
                        return i;
                    } else {
                        logger.warn("配针缓存位 {} Redis显示空闲但DB显示有货，状态: {}, 数量: {}",
                                i, dbNeedleCache.getStatus(), dbNeedleCache.getDrillCount());
                    }
                } else {
                    // 如果数据库中没有记录，认为可用
                    logger.info("找到可用配针缓存位: {} (数据库无记录)", i);
                    return i;
                }
            }
        }
        logger.warn("未找到可用的配针缓存位置");
        return 0;
    }

    // 辅助方法：查找空闲单元格
    private int findEmptyCell(DbUtils dbUtils) {
        String sql = "select * from wms_cell_info where drill_size is null or trim(drill_size)=''";
        List<Map<String, Object>> result = dbUtils.executeQuery(sql);
        return result == null || result.isEmpty() ? 0 : ((Integer) result.get(0).get("cell_id"));
    }

    // 辅助方法：写入寄存器并生成任务
    private void writeAndGenerateTask(ModbusTcpService modbusTcpService, WmsTxnInfo wmsTxnInfo, String macCode, int place, Long m_Drill_PortID, Long m_Drill_ID, Long drillCount) throws ModbusTransportException {
        modbusTcpService.writeHoldingRegister(slaveId, 558, m_Drill_PortID.intValue());
        genCallItemcodeTask(wmsTxnInfo, macCode, BusinessConstants.TASK_TYPE_1, drillCount, "508", m_Drill_PortID.toString(), "", "", "");
        modbusTcpService.writeHoldingRegister(slaveId, 559, place);
        genCallItemcodeTask(wmsTxnInfo, macCode, BusinessConstants.TASK_TYPE_1, drillCount, "509", place + "", "", "", "");
        modbusTcpService.writeHoldingRegister(slaveId, 510, m_Drill_ID.intValue());
        genCallItemcodeTask(wmsTxnInfo, macCode, BusinessConstants.TASK_TYPE_1, drillCount, "510", m_Drill_ID.toString(), "", "", "");
    }

    // 辅助方法：更新单元格状态
    private void updateCellStatus(WmsCellInfoMapper mapper, int place, String status) {
        WmsCellInfo wmsCellInfoDB = mapper.selectWmsCellInfoByCellId((long) place);
        if (wmsCellInfoDB != null) {
            wmsCellInfoDB.setCellStatus(status);
            mapper.updateWmsCellInfo(wmsCellInfoDB);
        }
    }

    // 辅助方法：更新配针缓存状态
    private void updateNeedleCacheStatus(Long drillId, int needlePlace, String drillInfo, Long drillCount, String status) {
        try {
            WmsNeedleCache wmsNeedleCache = wmsNeedleCacheMapper.selectWmsNeedleCacheByNeedleId((long) needlePlace);
            if (wmsNeedleCache != null) {
                wmsNeedleCache.setStatus(status);
                wmsNeedleCache.setDrillInfo(drillInfo);
                wmsNeedleCache.setDrillCount(drillCount);
                wmsNeedleCache.setUpdateTime(DateUtils.getNowDate());
                wmsNeedleCacheMapper.updateWmsNeedleCache(wmsNeedleCache);
                logger.info("成功更新配针缓存位 {} 状态为: {}", needlePlace, status);
            } else {
                logger.warn("未找到配针缓存位: {}", needlePlace);
            }
        } catch (Exception e) {
            logger.error("更新配针缓存状态失败，缓存位: {}, 状态: {}", needlePlace, status, e);
        }
    }

    // 辅助方法：处理满盒请求
    private int handleFullBoxRequest(JSONObject jsonObject, WmsTxnInfo wmsTxnInfo, String macCode, Long drillCount, String drillInfo, Long m_Drill_ID, ModbusTcpService modbusTcpService) {
        jsonObject.put("m_Drill_Info", drillInfo);
        jsonObject.put("m_Drill_Count", drillCount);
        jsonObject.put("txn_id", UUID.randomUUID().toString());

        String jsonString = jsonObject.toJSONString();
        logger.info("满盒请求: " + jsonString);

        try {
            String resultMaterial = HttpUtils.postData(requestMaterial, jsonString);
            logger.info("满盒返回包: " + resultMaterial);

            JSONObject response = JSONObject.parseObject(resultMaterial);
            if ("ok".equals(response.getString("Message"))) {
                genCallItemcodeTask(wmsTxnInfo, macCode, BusinessConstants.TASK_TYPE_3, drillCount, "503", m_Drill_ID.toString(), "", "", "");
            }
        } catch (Exception e) {
            logger.error("满盒请求失败", e);
            return 2;
        }

        return 2;
    }

    // 辅助方法：处理缓存请求
    private int handleCacheRequest(JSONObject jsonObject, WmsTxnInfo wmsTxnInfo, String macCode, Long drillCount, String drillInfo, ModbusTcpService modbusTcpService) {
        jsonObject.put("m_Drill_Info", drillInfo);
        jsonObject.put("m_Drill_Count", drillCount);
        jsonObject.put("txn_id", UUID.randomUUID().toString());

        String jsonString = jsonObject.toJSONString();
        logger.info("缓存请求: " + jsonString);

        try {
            String resultMaterial = HttpUtils.postData(requestMaterial, jsonString);
            logger.info("缓存返回包: " + resultMaterial);

            JSONObject response = JSONObject.parseObject(resultMaterial);
            if ("ok".equals(response.getString("Message"))) {
                try {
                    int placeid = 0;
                    modbusTcpService.writeHoldingRegister(slaveId, 553, placeid);
                    genCallItemcodeTask(wmsTxnInfo, macCode, BusinessConstants.TASK_TYPE_3, drillCount, "553", placeid + "", "", "", "");
                } catch (ModbusTransportException e) {
                    logger.error("写入寄存器地址失败", e);
                    return 5;
                }
            }
        } catch (Exception e) {
            logger.error("缓存请求失败", e);
            return 5;
        }

        return 0;
    }

    // 辅助方法：写入回流任务
    private void writeBackflowTasks(ModbusTcpService modbusTcpService, WmsTxnInfo wmsTxnInfo, String macCode, Long m_Drill_ID, Long m_Drill_PortID, int place, Long drillCount, WmsNeedleCache wmsNeedleCache) throws ModbusTransportException {
        modbusTcpService.writeHoldingRegister(slaveId, 517, m_Drill_ID.intValue());
        modbusTcpService.writeHoldingRegister(slaveId, 555, m_Drill_PortID.intValue());
        modbusTcpService.writeHoldingRegister(slaveId, 556, place);

        genCallItemcodeTask(wmsTxnInfo, macCode, BusinessConstants.TASK_TYPE_2, drillCount, "517", m_Drill_ID.toString(), "", wmsNeedleCache.getDrillInfo(), wmsNeedleCache.getDrillInfo());
        genCallItemcodeTask(wmsTxnInfo, macCode, BusinessConstants.TASK_TYPE_2, drillCount, "555", m_Drill_PortID.toString(), "", wmsNeedleCache.getDrillInfo(), wmsNeedleCache.getDrillInfo());
        genCallItemcodeTask(wmsTxnInfo, macCode, BusinessConstants.TASK_TYPE_2, drillCount, "556", place + "", "", wmsNeedleCache.getDrillInfo(), wmsNeedleCache.getDrillInfo());
    }

    private void genCallItemcodeTask(WmsTxnInfo wmsTxnInfo, String macCode, String taskType, Long drillCount, String plcAddress, String plcValue, String boxCode, String boxData, String drillInfo) {
        WmsTaskInfo wmsTaskInfo = new WmsTaskInfo();
        wmsTaskInfo.setMacCode(macCode);

        wmsTaskInfo.setTxnId(wmsTxnInfo.getTxnId());
//        wmsTaskInfo.setTaskId(java.util.UUID.randomUUID().toString());
        wmsTaskInfo.setMaterialCount(drillCount);
        wmsTaskInfo.setMaterialSrc(BusinessConstants.MATERIAL_SRC_1);
        wmsTaskInfo.setCreateTime(DateUtils.getNowDate());
        wmsTaskInfo.setUpdateBy(BusinessConstants.GENERATOR_RECORD_AUTHOR);
        wmsTaskInfo.setTaskStatus(BusinessConstants.TASK_STATUS_1);

        wmsTaskInfo.setTaskType(taskType);
        wmsTaskInfo.setBoxCode(boxCode);
        wmsTaskInfo.setBoxData(boxData);
        wmsTaskInfo.setDrillInfo(drillInfo);
        wmsTaskInfo.setPlcAddr(plcAddress);
        wmsTaskInfo.setPlcValue(plcValue);
        wmsTaskInfo.setTaskStatus(BusinessConstants.TASK_STATUS_1);
//        wmsTaskInfo.setPortId();
//        wmsTaskInfo.setsColumn();
//        wmsTaskInfo.setsRow();

        wmsTaskInfoMapper.insertWmsTaskInfo(wmsTaskInfo);
    }
}
